//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
using OpenLS.Core.Serialization;

namespace OpenLS.Spreadsheet.Internals
{
    public partial class Font : IOfficeXmlSerializable, INotifyPropertyChanged
    {

#if DEBUG
        public override string ToString()
        {
            return string.Format("{0}{1} {2} {3}, {4}", base.ToString() + GetHashCode(), (string) this.Name, fontWeight, fontStyle, FontFamily);
        }
#endif
        public Font(FontFamily fontFamily)
        {
#if DEBUG
            UnFreeze();
#endif
            this.FontFamily = fontFamily;
#if DEBUG
            Freeze();
#endif
        }
        public Font(FontFamily fontFamily, Action<Font> initializer)
        {
#if DEBUG
            UnFreeze();
#endif
            this.FontFamily = fontFamily;
            initializer(this);
#if DEBUG
            Freeze();
#endif
        }
        public Font(Action<Font> initializer)
        {
#if DEBUG
            UnFreeze();
#endif
            initializer(this);
#if DEBUG
            Freeze();
#endif
        }
        public Font()
        {
            
        }
        public override int GetHashCode()
        {
            int result = _size.GetHashCode();
            if (_color != null)
                result += _color.GetHashCode();
            if (FontFamily != null)
                result += FontFamily.GetHashCode();
            result += FontStyle.GetHashCode();
            result += FontWeight.GetHashCode();
            result += Underline.GetHashCode();
            if (Name != null)
                result += Name.GetHashCode();
            //\\if (this.Scheme != null)
          //\\  result += Scheme.GetHashCode();
            return result;

        }
#if DEBUG
        public string GetHashTrace()
        {

            string result = "fontid = " + base.GetHashCode().ToString();
            result += _size.GetHashCode();
            if (_color != null)
                result += "color" + _color.GetHashCode() + " " + _color;
            if (FontFamily != null)
                result += "FontFamily" + FontFamily.GetHashCode();
            result += "FontStyle" + FontStyle.GetHashCode();
            result += "FontWeight" + FontWeight.GetHashCode();
            result += "Underline" + Underline.GetHashCode();
            if (Name != null)
                result += "Name" + Name.GetHashCode();
            //\\if (this.Scheme != null)
           //\\ result += "Scheme" + Scheme.GetHashCode();
            return result;

        }
#endif
        public override bool Equals(object obj)
        {
            Contract.Ensures(!Contract.Result<bool>() || obj == null || GetHashCode() == obj.GetHashCode());
            if (obj is Font)
                return Equals((Font)obj);
            return false;
        }
        public bool Equals(Font f)
        {
            Contract.Requires(f != null);
            Contract.Ensures(!Contract.Result<bool>()  || GetHashCode() == f.GetHashCode());
            if (f._size != _size)
                return false;
            if (!object.Equals(f.FontFamily, FontFamily))
                return false;
            if (!Equals(f.Foreground, Foreground))
                return false;
            if (f.Underline != Underline)
                return false;
            if (f.FontStyle != FontStyle)
                return false;
            if (f.FontWeight != FontWeight)
                return false;
            if (f.Name != Name)
                return false;
           // if (f.Scheme != Scheme)
             //   return false;
            return true;
        }
        private double _size = 11;

        public double Size
        {
            get { return _size; }
            set
            {
#if DEBUG
                Contract.Assert(!isFrozen);
#endif
                _size = value;
                NotifyPropertyChanged("Size");
            }
        }

        private string _name;
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
#if DEBUG
                Contract.Assert(!isFrozen);
#endif
                _name = value;
            }
        }

        private SpreadsheetColor _color = Colors.Black;

        internal SpreadsheetColor Foreground
        {
            get { return _color; }
            set
            {
#if DEBUG
                Contract.Assert(!isFrozen);
#endif
                _color = value;
                NotifyPropertyChanged("Foreground");
            }
        }

        private FontWeight fontWeight;
        public FontWeight FontWeight
        {
            get { return fontWeight; }
            set
            {
#if DEBUG
                Contract.Assert(!isFrozen);
#endif
                fontWeight = value;
                NotifyPropertyChanged("FontWeight");
            }
        }
        private FontStyle fontStyle;
        public FontStyle FontStyle
        {
            get { return fontStyle; }
            set
            {
#if DEBUG
                Contract.Assert(!isFrozen);
#endif
                fontStyle = value;
                NotifyPropertyChanged("FontStyle");
            }
        }
        private UnderlineType underline;
        public UnderlineType Underline
        {
            get { return underline; }
            set
            {
#if DEBUG
                Contract.Assert(!isFrozen);
#endif
                underline = value;
                NotifyPropertyChanged("Underline");
            }
        }

        private int? _family;
        public int? Family
        {
            get { return _family; }
            set
            {
#if DEBUG

                Contract.Assert(!isFrozen);
#endif
                _family = value;
            }
        }

        private int? _charset;
        public int? Charset
        {
            get { return _charset; }
            set
            {
#if DEBUG
                Contract.Assert(!isFrozen);
#endif
                _charset = value;
            }
        }

        private FontSchemeType _scheme;
        internal FontSchemeType Scheme
        {
            get { return _scheme; }
            set
            {
                _scheme = value;
            }
        }

        private FontFamily _fontFamily;
#if DEBUG
        private bool isFrozen = true;
#endif

        public FontFamily FontFamily
        {
            get { return _fontFamily; }
            set
            {
#if DEBUG
                // SJE 11-07
                // Contract.Assert(!isFrozen);
                if (!isFrozen)
                    return;

#endif
                _fontFamily = value;
                NotifyPropertyChanged("FontFamily");
            }
        }
        public bool Strike { get; set; }
        public bool Outline { get; set; }
        public bool Shadow { get; set; }
        public bool Condense { get; set; }
        public bool Extend { get; set; }
        public VerticalRunAlignment VerticalAlignment { get; set; }

        internal Font Clone()
        {
            return MemberwiseClone() as Font;
        }
        internal Font CloneExcept(Action<Font> action)
        {
            Font result = Clone();
#if DEBUG
            result.isFrozen = false;
#endif
            action(result);
#if DEBUG
            result.isFrozen = true;
#endif
            return result;
        }

        #region IOfficeXmlSerializable Members

        void IOfficeXmlSerializable.ReadXml(ReadContext context)
        {
            using (ReadContext c = context.Read("font"))
            {
                c.PassAttributes();
#if DEBUG
                UnFreeze();
#endif
                Scheme = FontSchemeType.None;
                while (c.ReaderLocalName != null)
                {
                    switch (c.ReaderLocalName)
                    {
                        case "name":
                            Name = c.ReadOptionalElementStringAttribute("name", "val");
                            if (Name != null && Scheme == FontSchemeType.None)
                                FontFamily = new FontFamily(Name);
                            break;
                        case "charset":
                            Charset = c.ReadOptionalElementIntegerAttribute("charset", "val", 0); break;
                        case "family":
                            Family = c.ReadOptionalElementIntegerAttribute("family", "val", 0); break;
                        case "b":
                            if (c.ReadOptionalElementBooleanAttribute("b", false))
                                FontWeight = FontWeights.Bold;
                            else
                                FontWeight = FontWeights.Normal; break;

                        case "i":
                            if (c.ReadOptionalElementBooleanAttribute("i", false))
                                FontStyle = FontStyles.Italic;
                            else
                                FontStyle = FontStyles.Normal; break;
                        case "strike":
                            Strike = c.ReadOptionalElementBooleanAttribute("strike", false);
                            break;
                        case "outline":
                            Outline = c.ReadOptionalElementBooleanAttribute("outline", false);
                            break;
                        case "shadow":
                            Shadow = c.ReadOptionalElementBooleanAttribute("shadow", false);
                            break;
                        case "extend":
                            Extend = c.ReadOptionalElementBooleanAttribute("extend", false);
                            break;
                        case "color":
                            //\\if (c.ReaderLocalName == "color")
                            {
                                //\\ using (ReadContext c2 = c.Read("color"))
                                {
                                    Foreground = SpreadsheetColor.ReadColor("color", c);
                                    //\\ Debug.Assert(ColorReference.GetColorReference(Foreground) != null);
                                }
                            } break;
                        case "sz":
                            Size = c.ReadOptionalElementDoubleAttribute("sz", "val", 11.0); break;
                        case "u":
                            Underline = c.ReadOptionalElementEnumAttribute("u", "val", UnderlineType.None, UnderlineType.Single);
                            break;
                        case "vertAlign":
                            VerticalAlignment = c.ReadElementEnumAttribute<VerticalRunAlignment>("vertAlign");
                            break;
                        case "scheme":
                            Scheme = c.ReadOptionalElementEnumAttribute("scheme", "val", FontSchemeType.None, FontSchemeType.None);
                            Workbook wb = context.GetData<Workbook>();
                            switch (Scheme)
                            {
                                case FontSchemeType.Major:
                                    FontFamily = wb.Theme.FontScheme.MajorFont.Latin; //\\
                                    break;
                                case FontSchemeType.Minor:
                                    FontFamily = wb.Theme.FontScheme.MinorFont.Latin; //\\
                                    break;
                            }
                            break;
                        case "condense":
                            Condense = c.ReadOptionalElementBooleanAttribute("condense", false, true);
                            break;
                        default: throw new NotImplementedException();
                    }
                }
#if DEBUG
                Freeze();
#endif
            }
        }

        void IOfficeXmlSerializable.WriteXml(WriteContext context)
        {
            using (WriteContext c = context.Write("font"))
            {
                if (Name != null)
                    c.WriteOptionalElementStringAttribute("name", Name);
                else if (FontFamily != null)
                    c.WriteOptionalElementStringAttribute("name", FontFamily.Source); //\\
                c.WriteOptionalElementIntegerAttribute("charset", Charset);
                c.WriteOptionalElementIntegerAttribute("family", Family);
                if (FontWeight != FontWeights.Normal)
                    c.WriteOptionalElementBooleanAttribute("b", true);
                if (FontStyle != FontStyles.Normal)
                    c.WriteOptionalElementBooleanAttribute("i", true);
                c.WriteOptionalElementBooleanAttribute("strike", Strike, false);
                c.WriteOptionalElementBooleanAttribute("outline", Outline, false);
                c.WriteOptionalElementBooleanAttribute("shadow", Shadow, false);
                c.WriteOptionalElementBooleanAttribute("condense", Condense, false);
                c.WriteOptionalElementBooleanAttribute("extend", Extend, false);
                if (Foreground != null)
                {
                    SpreadsheetColor r = Foreground;
                    r.WriteXmlAs("color", c);

                }
                c.WriteOptionalElementDoubleAttribute("sz", "val", Size, 11.0);
                c.WriteOptionalElementEnumAttribute("u", "val", Underline, UnderlineType.None, UnderlineType.Single);
                c.WriteOptionalElementEnumAttribute("vertAlign", VerticalAlignment, VerticalRunAlignment.Baseline, VerticalRunAlignment.Baseline);
                //\\   PreWriteXml(context);
                c.WriteOptionalElementEnumAttribute("scheme", Scheme, FontSchemeType.None, FontSchemeType.None);
            }
        }

        internal void PreWriteXml(WriteContext context)
        {
            Workbook wb = context.GetData<Workbook>();
            if (wb != null && wb.Theme != null && wb.Theme.FontScheme != null && FontFamily != null)
            {
                Scheme = (FontSchemeType)wb.Theme.FontScheme.GetIndex(FontFamily);
            }
        }

        #endregion



        internal void ReadXml(ReadContext cFonts)
        {
            IOfficeXmlSerializable s = this;
            s.ReadXml(cFonts);
        }

        public event PropertyChangedEventHandler PropertyChanged;
        void NotifyPropertyChanged(string propertyName)
        {
            Contract.Requires(GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null);
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
#if DEBUG
        public void Freeze()
        {
            isFrozen = true;
        }
        public void UnFreeze()
        {
            isFrozen = false;
        }
#endif
    }
}